package com.information.manage.basic.audit.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.information.manage.basic.audit.constant.AuditTaskStatusEnum;
import com.information.manage.basic.audit.constant.AuditTypeEnum;
import com.information.manage.basic.audit.constant.ShrlxEnum;
import com.information.manage.basic.audit.mapper.*;
import com.information.manage.basic.audit.model.dto.InitAuditTaskDataDto;
import com.information.manage.basic.audit.model.entity.*;
import com.information.manage.basic.audit.model.query.AuditCurrentTasksQuery;
import com.information.manage.basic.audit.model.query.FindAuditTaskQuery;
import com.information.manage.basic.audit.model.vo.AuditTaskPageVO;
import com.information.manage.basic.audit.service.AuditResultService;
import com.information.manage.basic.audit.service.AuditTaskService;
import com.information.manage.basic.common.result.Result;
import com.information.manage.basic.common.token.TokenUtils;
import com.information.manage.basic.common.utils.RedisUtils;
import com.information.manage.basic.common.utils.SpringContextUtil;
import com.information.manage.basic.model.entity.SysUserDO;
import com.information.manage.basic.model.vo.LoginUserInfoVO;
import com.information.manage.basic.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AuditTaskServiceImpl extends ServiceImpl<AuditTaskMapper, AuditTaskDO> implements AuditTaskService {

    @Autowired
    private AuditTaskMapper auditTaskMapper;

    @Autowired
    private AuditLevelMapper auditLevelMapper;

    @Autowired
    private AuditUserMapper auditUserMapper;

    @Autowired
    private AuditTaskLevelMapper auditTaskLevelMapper;

    @Autowired
    private AuditTaskLevelUserMapper auditTaskLevelUserMapper;

    @Autowired
    private AuditResultService auditResultService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public void initAuditTask(AuditModelDO auditModelDO, InitAuditTaskDataDto initAuditTaskDataDto, LoginUserInfoVO userInfo) {
        this.handleInitAuditTask(auditModelDO, initAuditTaskDataDto, userInfo);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public AuditTaskDO handleInitAuditTask(AuditModelDO auditModelDO, InitAuditTaskDataDto initAuditTaskDataDto, LoginUserInfoVO userInfo) {
        //根据审核流程获取层级审核列表
        List<AuditLevelDO> auditLevelDOList = auditLevelMapper.selectList(new LambdaQueryWrapper<AuditLevelDO>()
                .eq(AuditLevelDO::getAuditModelId, auditModelDO.getId()).orderByAsc(AuditLevelDO::getLevel));
        Assert.isTrue(CollectionUtils.isNotEmpty(auditLevelDOList), "审核层级数据缺失,请联系管理员");
        //根据审核模板查找到第一个
        AuditLevelDO firstAuditItem = auditLevelDOList.get(0);

        //生成审核主任务
        AuditTaskDO auditTaskDO = buildAuditTask(auditModelDO, firstAuditItem, initAuditTaskDataDto, userInfo);
        auditTaskMapper.insert(auditTaskDO);

        //一次性生成全部的层级审核子任务
        //是否触发了主任务流程校验
        Boolean processCheck = false;
        List<AuditTaskLevelDO> auditTaskLevelDOList = new LinkedList<>();
        AuditTaskLevelDO firstShrwcj = null;
        for (AuditLevelDO auditLevelDO : auditLevelDOList) {
            AuditTaskLevelDO auditTaskLevelDO = buildAuditTaskItem(auditTaskDO, auditLevelDO, initAuditTaskDataDto);
            auditTaskLevelMapper.insert(auditTaskLevelDO);

            if (auditLevelDO.getLevel() == 1) {  // 设置第一层级为主任务
                firstShrwcj = auditTaskLevelDO;
                //设置主任务的正在执行的当前子任务ID
                auditTaskDO.setCurrentAuditTaskLevelId(auditTaskLevelDO.getId());
                auditTaskMapper.updateById(auditTaskDO);
            }
            auditTaskLevelDOList.add(auditTaskLevelDO);

            //查询层级的审核人员列表
            List<AuditUserDO> auditUserDOList = auditUserMapper.selectList(new LambdaQueryWrapper<AuditUserDO>().eq(AuditUserDO::getAuditLevelId, auditLevelDO.getId()));
            Assert.isTrue(CollectionUtils.isNotEmpty(auditUserDOList), "层级审核人列表为空,请联系管理员");
            Date date = new Date();
            //保存层级审核子任务和审核人员的映射
            for (AuditUserDO auditUserDO : auditUserDOList) {
                AuditTaskLevelUserDO auditTaskLevelUserDO = new AuditTaskLevelUserDO();
                auditTaskLevelUserDO.setAuditTaskId(auditTaskDO.getId());
                auditTaskLevelUserDO.setAuditTaskLevelId(auditTaskLevelDO.getId());
                auditTaskLevelUserDO.setType(auditUserDO.getType());
                auditTaskLevelUserDO.setAuditObjectId(auditUserDO.getAuditObjectId());
                //如果自动通过开启,且任务发起人和审核人是同一个则自动通过
                if (auditModelDO.getAutoPass() == 1) {
                    if ((auditUserDO.getType().equalsIgnoreCase(ShrlxEnum.USER.name()) && auditTaskDO.getCreateUserId().equals(auditUserDO.getAuditObjectId())
                    )) {   // 需要处理角色包含关系时也自动通过
                        auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
                        auditTaskLevelUserDO.setAuditRemark("自动通过");
                        //如果为第一级审核则触发了主任务的流程校验
                        if (auditTaskLevelDO.getAuditLevel() == 1) {
                            processCheck = true;
                        }
                    }
                } else {
                    auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.IN_PROCESS.getStatus());
                }
                auditTaskLevelUserDO.setCreateTime(date);
                auditTaskLevelUserDO.setUpdateTime(date);
                auditTaskLevelUserMapper.insert(auditTaskLevelUserDO);
            }
        }
        //如果触发了主任务流程校验,则需要一层一层查看当前审核层级是否通过走向下一层
        if (processCheck) {
            //这里必须传入当前任务的第一审核层级任务即审核任务开始
            handlePassAuditTaskProcess(auditTaskDO, firstShrwcj);
        }
        return auditTaskDO;
    }

    /**
     * 构建层级审核任务对象
     *
     * @param auditTaskDO
     * @param auditLevelDO
     * @return
     */
    private AuditTaskLevelDO buildAuditTaskItem(AuditTaskDO auditTaskDO, AuditLevelDO auditLevelDO, InitAuditTaskDataDto initAuditTaskDataDto) {
        AuditTaskLevelDO auditTaskLevelDO = new AuditTaskLevelDO();
        Date date = new Date();
        auditTaskLevelDO.setAuditTaskId(auditTaskDO.getId());
        auditTaskLevelDO.setAuditType(auditTaskDO.getType());
        auditTaskLevelDO.setAuditLevelId(auditLevelDO.getId());
        String name = auditLevelDO.getName();
        if (StringUtils.isNotBlank(name)) auditTaskLevelDO.setAuditLevelName(name);
        auditTaskLevelDO.setAuditLevel(auditLevelDO.getLevel());
        auditTaskLevelDO.setType(auditLevelDO.getType());
        auditTaskLevelDO.setPassMethod(auditLevelDO.getPassMethod());
        auditTaskLevelDO.setStatus(AuditTaskStatusEnum.IN_PROCESS.getStatus()); //任务初始化时默认审核中
        auditTaskLevelDO.setCreateUserId(initAuditTaskDataDto.getUserId());
        auditTaskLevelDO.setCreateUserName(initAuditTaskDataDto.getUserName());
        auditTaskLevelDO.setCreateTime(date);
        auditTaskLevelDO.setUpdateTime(date);
        return auditTaskLevelDO;
    }

    /**
     * 构建审核主任务对象
     *
     * @param auditModelDO   审核模板
     * @param firstAuditItem 审核第一层级
     * @return
     */
    private AuditTaskDO buildAuditTask(AuditModelDO auditModelDO, AuditLevelDO firstAuditItem, InitAuditTaskDataDto initAuditTaskDataDto, LoginUserInfoVO userInfo) {
        AuditTaskDO auditTaskDO = new AuditTaskDO();
        Date date = new Date();
        String mainId = initAuditTaskDataDto.getMainId();
        auditTaskDO.setMainId(mainId);
        auditTaskDO.setType(AuditTypeEnum.OTHER.name());
        auditTaskDO.setName(initAuditTaskDataDto.getTitle());
        auditTaskDO.setAuditModelId(auditModelDO.getId());
        auditTaskDO.setDuplicateRemoval(auditModelDO.getDuplicateRemoval());
        auditTaskDO.setAutoPass(auditModelDO.getAutoPass());
        auditTaskDO.setCurrentAuditLevelId(firstAuditItem.getId());
        auditTaskDO.setCurrentAuditLevel(firstAuditItem.getLevel());
        auditTaskDO.setCurrentType(firstAuditItem.getType());
        auditTaskDO.setStatus(AuditTaskStatusEnum.IN_PROCESS.getStatus());
        auditTaskDO.setCreateUserId(userInfo.getId().toString());
        auditTaskDO.setCreateUserName(userInfo.getName());
        auditTaskDO.setCreateTime(date);
        auditTaskDO.setUpdateTime(date);
        return auditTaskDO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
    public void handlePassAuditTaskProcess(AuditTaskDO auditTaskDO, AuditTaskLevelDO currentAuditTaskLevelDO) {
        //此时传入进来的审核任务的当前审核层级和当前审核任务项因该是一致的
        //查询当前层级已经同意的人数
        Integer passNumber = this.auditTaskLevelUserMapper.selectCount(new LambdaQueryWrapper<AuditTaskLevelUserDO>()
                .eq(AuditTaskLevelUserDO::getAuditTaskLevelId, currentAuditTaskLevelDO.getId())
                .eq(AuditTaskLevelUserDO::getStatus, 1));
        if (currentAuditTaskLevelDO.getPassMethod() == 0) {   //会签，即需要所有审核人都同意,这一层级才会结束,审核任务才会走向下一层级或者整个审核任务结束
            //查询当前审核层级是否所有审核人都同意了
            //查询当前层级总审核人数
            Integer needTotalPassNumber = this.auditTaskLevelUserMapper.selectCount(new LambdaQueryWrapper<AuditTaskLevelUserDO>()
                    .eq(AuditTaskLevelUserDO::getAuditTaskLevelId, currentAuditTaskLevelDO.getId()));
            if (passNumber.intValue() == needTotalPassNumber.intValue()) {
                //所有会签的审核人员都同意了，当前审核层级任务结束，走向向一审核层级
                //如果没有下一层级审核则整合审核任务流程结束
                completeCurrentTaskAndStepInfoNext(auditTaskDO, currentAuditTaskLevelDO);
            } else {
                //为满足所有审核人员同意的条件，流程停留在当前审核层级
                //更新审核任务的当前审核层级
                auditTaskDO.setCurrentAuditLevel(currentAuditTaskLevelDO.getAuditLevel());
                auditTaskDO.setCurrentAuditLevelId(currentAuditTaskLevelDO.getAuditLevelId());
                auditTaskDO.setCurrentAuditTaskLevelId(currentAuditTaskLevelDO.getId());
                auditTaskDO.setUpdateTime(new Date());
                this.auditTaskMapper.updateById(auditTaskDO);
            }
        } else {
            //或签即只要一个人同意,这一层级就会结束,审核任务走向下一层级或者整个审核任务结束
            if (passNumber.intValue() > 0) {
                completeCurrentTaskAndStepInfoNext(auditTaskDO, currentAuditTaskLevelDO);
            }
        }
    }

    /**
     * 完成当前审核层级任务,并进入下一层级审核任务,如果没有下一层级审核任务则整个审核任务结束
     *
     * @param auditTaskDO
     * @param currentAuditTaskLevelDO
     */
    private void completeCurrentTaskAndStepInfoNext(AuditTaskDO auditTaskDO, AuditTaskLevelDO currentAuditTaskLevelDO) {
        //更新当前审核层级任务结束
        currentAuditTaskLevelDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
        currentAuditTaskLevelDO.setAuditRemark(AuditTaskStatusEnum.PASS.getDescription());
        currentAuditTaskLevelDO.setUpdateTime(new Date());
        this.auditTaskLevelMapper.updateById(currentAuditTaskLevelDO);

        //查询下一层级审核
        AuditTaskLevelDO nextAuditTaskLevelDO = this.auditTaskLevelMapper.selectOne(new LambdaQueryWrapper<AuditTaskLevelDO>()
                .eq(AuditTaskLevelDO::getAuditTaskId, auditTaskDO.getId())
                .eq(AuditTaskLevelDO::getAuditLevel, currentAuditTaskLevelDO.getAuditLevel() + 1));
        if (nextAuditTaskLevelDO == null) {
            //如果没有下一层级审核则整合审核任务流程结束
            auditTaskDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
            auditTaskDO.setAuditRemark(AuditTaskStatusEnum.PASS.getDescription());
            auditTaskDO.setUpdateTime(new Date());
            this.auditTaskMapper.updateById(auditTaskDO);
            // 审核任务通过后，根据不同类型模板需要完成不同的业务功能
            auditResultService.handlePassAuditTaskAll(auditTaskDO);
            return;
        }

        //更新审核任务的当前审核层级
        auditTaskDO.setCurrentAuditLevel(nextAuditTaskLevelDO.getAuditLevel());
        auditTaskDO.setCurrentAuditLevelId(nextAuditTaskLevelDO.getAuditLevelId());
        auditTaskDO.setCurrentAuditTaskLevelId(nextAuditTaskLevelDO.getId());
        auditTaskDO.setUpdateTime(new Date());
        this.auditTaskMapper.updateById(auditTaskDO);
        auditResultService.handlePassAuditTask(auditTaskDO);

        //递归调用进入下一层级审核
        handlePassAuditTaskProcess(auditTaskDO, nextAuditTaskLevelDO);
    }

    @Override
    public Result auditTasksPage(HttpServletRequest request, FindAuditTaskQuery findAuditTaskQuery) {
        // 获取到用户信息，只查询当前用户的审批信息
        Integer userId = TokenUtils.getUserId(org.springframework.util.StringUtils.isEmpty(request.getHeader("token"))
                ? request.getAttribute("token").toString() : request.getHeader("token"));
        LoginUserInfoVO userInfo = sysUserService.getUserInfo(userId);
        Assert.isTrue(userInfo != null, "不存在登录用户信息");
        Integer roleId = userInfo.getRoleId();
        List<String> roles = roleId == null ? null : Arrays.asList(userInfo.getRoleId().toString());
        Page<AuditTaskDO> page;
        Boolean myApprove = findAuditTaskQuery.getMyApprove();
        if (myApprove == null) myApprove = Boolean.TRUE;
        if (myApprove) {  // 查询待我审核
            page = auditTaskMapper.findAuditTasksProcessPage(new Page<>(findAuditTaskQuery.getCurPage(), findAuditTaskQuery.getPageSize())
                    , AuditTypeEnum.OTHER.name(), null, findAuditTaskQuery.getName(), null, null, null, null, userId.toString(), roles);
        } else {  // 查询我已审核的
            page = auditTaskMapper.findAuditTasksApprovedPage(new Page<>(findAuditTaskQuery.getCurPage(), findAuditTaskQuery.getPageSize())
                    , AuditTypeEnum.OTHER.name(), null, null, null, findAuditTaskQuery.getStatusList(), null, null, userId.toString(), roles);
        }
        List<String> mainIds = page.getRecords().stream().map(AuditTaskDO::getMainId).collect(Collectors.toList());
        Map<String, List<AuditTaskDO>> map = auditTaskMapper.selectList(new LambdaQueryWrapper<AuditTaskDO>().in(AuditTaskDO::getMainId, mainIds).orderByAsc(AuditTaskDO::getId))
                .stream().collect(Collectors.groupingBy(
                        AuditTaskDO::getMainId,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                (List<AuditTaskDO> list) -> list.stream()
                                        .sorted(Comparator.comparing(AuditTaskDO::getId))
                                        .collect(Collectors.toList())
                        )
                ));
        List<Long> currentAuditTaskLevelIds = page.getRecords().stream().map(AuditTaskDO::getCurrentAuditTaskLevelId).collect(Collectors.toList());
        Map<Long, AuditTaskLevelUserDO> collect = auditTaskLevelUserMapper.selectList(new LambdaQueryWrapper<AuditTaskLevelUserDO>().in(AuditTaskLevelUserDO::getAuditTaskLevelId, currentAuditTaskLevelIds))
                .stream().collect(Collectors.toMap(k -> k.getAuditTaskLevelId(), v -> v));
        List<AuditTaskPageVO> list = new ArrayList<>();
        for (AuditTaskDO record : page.getRecords()) {
            AuditTaskPageVO auditTaskPageVO = new AuditTaskPageVO();
            BeanUtils.copyProperties(record, auditTaskPageVO);
            List<AuditTaskDO> auditTaskDOS = map.get(record.getMainId());
            auditTaskPageVO.setFirstName(auditTaskDOS.get(0).getName());
            AuditTaskLevelUserDO auditTaskLevelUserDO = collect.get(record.getCurrentAuditTaskLevelId());
            if (auditTaskLevelUserDO != null) auditTaskPageVO.setPreAuditRemark(auditTaskLevelUserDO.getAuditRemark());
            list.add(auditTaskPageVO);
        }
        Page<AuditTaskPageVO> resPage = new Page<>();
        resPage.setRecords(list);
        resPage.setPages(page.getPages());
        resPage.setSize(page.getSize());
        resPage.setCurrent(page.getCurrent());
        resPage.setTotal(page.getTotal());
        resPage.setOrders(page.getOrders());
        return Result.ok(resPage);
    }

    @Override
    public void cancelProcessAuditTasks(String mainId) {
        List<AuditTaskDO> auditTaskDOS = auditTaskMapper.selectList(new LambdaQueryWrapper<AuditTaskDO>()
                .eq(AuditTaskDO::getMainId, mainId)
                .eq(AuditTaskDO::getStatus, AuditTaskStatusEnum.IN_PROCESS.getStatus()));
        // 一般情况下 不会出现多条  只会存在一条任务正在执行中
        for (AuditTaskDO auditTaskDO : auditTaskDOS) {
            List<AuditTaskLevelDO> auditTaskLevelDOList = this.auditTaskLevelMapper.selectList(new LambdaQueryWrapper<AuditTaskLevelDO>()
                    .eq(AuditTaskLevelDO::getAuditTaskId, auditTaskDO.getId()));
            if (CollectionUtils.isNotEmpty(auditTaskLevelDOList)) {
                for (AuditTaskLevelDO auditTaskLevelDO : auditTaskLevelDOList) {
                    List<AuditTaskLevelUserDO> auditTaskLevelUserDOS = this.auditTaskLevelUserMapper.selectList(new LambdaQueryWrapper<AuditTaskLevelUserDO>()
                            .eq(AuditTaskLevelUserDO::getAuditTaskLevelId, auditTaskLevelDO.getId()));
                    if (CollectionUtils.isNotEmpty(auditTaskLevelUserDOS)) {
                        for (AuditTaskLevelUserDO auditTaskLevelUserDO : auditTaskLevelUserDOS) {
                            this.auditTaskLevelUserMapper.deleteById(auditTaskLevelUserDO.getId());
                        }
                    }
                    this.auditTaskLevelMapper.deleteById(auditTaskLevelDO.getId());
                }
            }
            this.auditTaskMapper.deleteById(auditTaskDO.getId());
        }
    }

    @Override
    public Result examineTask(HttpServletRequest request, AuditCurrentTasksQuery auditCurrentTasksQuery) {
        Integer userId = TokenUtils.getUserId(org.springframework.util.StringUtils.isEmpty(request.getHeader("token"))
                ? request.getAttribute("token").toString() : request.getHeader("token"));
        LoginUserInfoVO userInfo = sysUserService.getUserInfo(userId);
        Assert.isTrue(userInfo != null, "用户信息不存在");
        //查询当前审核层级
        List<Long> auditTaskLevelIds = auditCurrentTasksQuery.getAuditTaskLevelIds();
        List<AuditTaskLevelDO> auditTaskLevelDOList = new LinkedList<>();
        for (Long auditTaskLevelId : auditTaskLevelIds) {
            AuditTaskLevelDO auditTaskLevelDO = this.auditTaskLevelMapper.selectById(auditTaskLevelId);
            Assert.notNull(auditTaskLevelDO, "层级审核任务不存在，请刷新后再试");
            auditTaskLevelDOList.add(auditTaskLevelDO);
        }
        if (CollectionUtils.isEmpty(auditTaskLevelDOList)) return Result.fail("不存在可执行的层级审核任务");
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);

        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (AuditTaskLevelDO auditTaskLevelDO : auditTaskLevelDOList) {
            CompletableFuture<Void> future = new CompletableFuture<>();
            futures.add(future);

            CompletableFuture.runAsync(() -> {
                try {
                    this.executeApprove(auditTaskLevelDO, userInfo, auditCurrentTasksQuery, successCount, failCount);
                    future.complete(null); // 标记任务完成
                } catch (Exception e) {
                    future.completeExceptionally(e); // 标记任务异常
                }
            });
        }

        // 在所有任务完成或有异常时触发
        try {
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .exceptionally(e -> {
                        return null;
                    }).join(); // 等待所有任务完成
        } catch (Exception e) {
            throw new RuntimeException(e.getCause().getMessage());
        }

        JSONObject data = new JSONObject();
        data.put("taskItemIds", auditCurrentTasksQuery.getAuditTaskLevelIds());
        data.put("approve", auditCurrentTasksQuery.getApprove());
        data.put("successCount", successCount);
        data.put("failCount", failCount);
        return new Result<>(data);
    }

    @Async("taskExecutor")
    @Override
    public void executeApprove(AuditTaskLevelDO auditTaskLevelDO, LoginUserInfoVO userInfo, AuditCurrentTasksQuery auditCurrentTasksQuery, AtomicInteger successCount, AtomicInteger failCount) {
        try {

            AuditTaskService proxy = (AuditTaskService) SpringContextUtil.getBean("auditTaskServiceImpl");
            // 同一时间只能有一个人审批 因此这里需要添加锁
            String lockKey = "audit_task_approve_" + auditTaskLevelDO.getAuditTaskId();
            if (redisUtils.setIfAbsent(lockKey, "lock", 3L, TimeUnit.MINUTES)) {
                try {
                    proxy.lockTaskAndApprove(auditTaskLevelDO, userInfo, auditCurrentTasksQuery);
                } catch (Exception e) {
                    //如果是业务校验错误则直接抛出给外层
                    if (e instanceof IllegalArgumentException) {
                        log.info("审批错误：{}", e.getMessage());
                        throw e;
                    }
                    log.error("审批任务时发生异常={}", e);
                    Assert.isTrue(false, "审批任务时发生异常");
                } finally {
                    redisUtils.remove(lockKey);
                }
            } else {
                // 没有拿到锁
                Assert.isTrue(false, "有其他审核人正在审批,请稍等后再试");
            }
            //审批任务执行成功
            successCount.incrementAndGet();
        } catch (Exception e) {
            //审批任务执行失败
            failCount.incrementAndGet();
            //如果是业务校验错误则直接抛出给外层
            if (e instanceof IllegalArgumentException) {
                throw e;
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void lockTaskAndApprove(AuditTaskLevelDO auditTaskLevelDO, LoginUserInfoVO userInfo, AuditCurrentTasksQuery auditCurrentTasksQuery) {
        //查询审核主任务
        AuditTaskDO auditTaskDO = this.auditTaskMapper.selectById(auditTaskLevelDO.getAuditTaskId());
        Assert.notNull(auditTaskDO, "审核任务不存在，请刷新后再试");
        //校验主任务流程是否未结束
        Assert.isTrue(auditTaskDO.getStatus() == AuditTaskStatusEnum.IN_PROCESS.getStatus(), "审核任务已经结束，请刷新后再试");
        //校验主任务的进度是否为当前层级审核
        Assert.isTrue(auditTaskDO.getCurrentAuditTaskLevelId().intValue() == auditTaskLevelDO.getId().intValue(), "非法的审核层级，请刷新后再试");
        Assert.isTrue(auditTaskLevelDO.getStatus() == AuditTaskStatusEnum.IN_PROCESS.getStatus(), "当前层级审核已经审批过，请刷新后再试");
        //查询当前层级审核的审核人是否有操作的用户
        List<AuditTaskLevelUserDO> auditTaskLevelUserDOS = this.auditTaskLevelUserMapper.selectList(new LambdaQueryWrapper<AuditTaskLevelUserDO>()
                .eq(AuditTaskLevelUserDO::getAuditTaskLevelId, auditTaskLevelDO.getId()));
        Boolean curAuthority = false;  // 判断当前用户是否具有审核权限
        if (CollectionUtils.isNotEmpty(auditTaskLevelUserDOS)) {
            for (AuditTaskLevelUserDO auditTaskLevelUserDO : auditTaskLevelUserDOS) {
                if (auditTaskLevelUserDO.getType().equalsIgnoreCase(ShrlxEnum.USER.name())) {  // 用户审核
                    if (auditTaskLevelUserDO.getAuditObjectId().equalsIgnoreCase(userInfo.getId().toString())) {
                        curAuthority = true;
                        Assert.isTrue(auditTaskLevelUserDO.getStatus() == AuditTaskStatusEnum.IN_PROCESS.getStatus(), "当前层级审核已经审批过，请刷新后再试");
                        //根据提交的审批结果更新status
                        if (auditCurrentTasksQuery.getApprove().equalsIgnoreCase(AuditTaskStatusEnum.PASS.name())) {
                            auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
                        } else {
                            auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.REJECT.getStatus());
                        }
                        auditTaskLevelUserDO.setAuditRemark(auditCurrentTasksQuery.getAuditRemark());
                        auditTaskLevelUserDO.setUpdateTime(new Date());
                        this.auditTaskLevelUserMapper.updateById(auditTaskLevelUserDO);
                    }
                } else { // 角色审核
                    if (userInfo.getRoleId().toString().equals(auditTaskLevelUserDO.getAuditObjectId())) {
                        curAuthority = true;
                        Assert.isTrue(auditTaskLevelUserDO.getStatus() == AuditTaskStatusEnum.IN_PROCESS.getStatus(), "当前层级审核已经审批过，请刷新后再试");
                        //根据提交的审批结果更新status
                        if (auditCurrentTasksQuery.getApprove().equalsIgnoreCase(AuditTaskStatusEnum.PASS.name())) {
                            auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
                        } else {
                            auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.REJECT.getStatus());
                        }
                        auditTaskLevelUserDO.setAuditRemark(auditCurrentTasksQuery.getAuditRemark());
                        auditTaskLevelUserDO.setUpdateTime(new Date());
                        this.auditTaskLevelUserMapper.updateById(auditTaskLevelUserDO);
                    }
                }
            }
        }
        Assert.isTrue(curAuthority, "当前用户不在审核人列表中，请刷新后再试");
        //只要有人驳回主审核任务立即结束
        if (auditCurrentTasksQuery.getApprove().equalsIgnoreCase(AuditTaskStatusEnum.REJECT.name())) {
            Date date = new Date();
            auditTaskDO.setStatus(AuditTaskStatusEnum.REJECT.getStatus());
            auditTaskDO.setAuditRemark(AuditTaskStatusEnum.REJECT.getDescription());
            auditTaskDO.setUpdateTime(date);
            this.auditTaskMapper.updateById(auditTaskDO);

            auditTaskLevelDO.setStatus(AuditTaskStatusEnum.REJECT.getStatus());
            auditTaskLevelDO.setAuditRemark(AuditTaskStatusEnum.REJECT.getDescription());
            auditTaskLevelDO.setUpdateTime(date);
            this.auditTaskLevelMapper.updateById(auditTaskLevelDO);

            this.auditResultService.handleRejectAuditTaskAll(auditTaskDO);
            //审核任务结束,方法返回
            return;
        }

        //如果是审批通过则继续任务流程
        if (auditTaskDO.getDuplicateRemoval() == 1) {  //检查是否开启自动去重
            passDuplicateUser(auditTaskLevelDO, userInfo);
        }

        // 处理审核通过后的审核任务流程执行
        handlePassAuditTaskProcess(auditTaskDO, auditTaskLevelDO);
    }

    /**
     * 实现自动去重功能</br>
     * 认定同一个用户出现在多个层级上，一个层级审批通过，则其他层级自动通过
     *
     * @param currentAuditTaskLevelDO 当前审核任务层级
     * @param userInfo                审核的用户
     */
    private void passDuplicateUser(AuditTaskLevelDO currentAuditTaskLevelDO, LoginUserInfoVO userInfo) {
        //查询下一层级审核
        AuditTaskLevelDO nextAuditTaskLevelDO = this.auditTaskLevelMapper.selectOne(new LambdaQueryWrapper<AuditTaskLevelDO>()
                .eq(AuditTaskLevelDO::getAuditTaskId, currentAuditTaskLevelDO.getAuditTaskId())
                .eq(AuditTaskLevelDO::getAuditLevel, currentAuditTaskLevelDO.getAuditLevel() + 1));
        if (nextAuditTaskLevelDO == null) {
            //如不存在下一层级审核递归结束
            return;
        }
        List<AuditTaskLevelUserDO> auditTaskLevelUserDOList = this.auditTaskLevelUserMapper.selectList(new LambdaQueryWrapper<AuditTaskLevelUserDO>()
                .eq(AuditTaskLevelUserDO::getAuditTaskLevelId, nextAuditTaskLevelDO.getId()));
        if (CollectionUtils.isNotEmpty(auditTaskLevelUserDOList)) {
            for (AuditTaskLevelUserDO auditTaskLevelUserDO : auditTaskLevelUserDOList) {
                if (auditTaskLevelUserDO.getType().equalsIgnoreCase(ShrlxEnum.USER.name())) {
                    if (auditTaskLevelUserDO.getAuditObjectId().equalsIgnoreCase(userInfo.getId().toString())) {
                        auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
                        auditTaskLevelUserDO.setAuditRemark("自动去重");
                        auditTaskLevelUserDO.setUpdateTime(new Date());
                        this.auditTaskLevelUserMapper.updateById(auditTaskLevelUserDO);
                    }
                }
                if (auditTaskLevelUserDO.getType().equalsIgnoreCase(ShrlxEnum.ROLE.name())) {
                    Integer roleId = userInfo.getRoleId();
                    if (roleId != null && roleId.toString().equals(auditTaskLevelUserDO.getAuditObjectId())) {
                        auditTaskLevelUserDO.setStatus(AuditTaskStatusEnum.PASS.getStatus());
                        auditTaskLevelUserDO.setAuditRemark("自动去重");
                        auditTaskLevelUserDO.setUpdateTime(new Date());
                        this.auditTaskLevelUserMapper.updateById(auditTaskLevelUserDO);
                    }
                }
            }
        }

        //递归下一层级审核查询审核人是否有当前的审批人
        passDuplicateUser(nextAuditTaskLevelDO, userInfo);
    }

    @Override
    public Result<AuditFeedDo> getAuditFeedByAuditTaskId(Integer auditTaskId) {

        // 通过查询audit_task表获取最新审核任务信息,查出来的结果如果有多条，则取创建时间最近的一条
        AuditTaskDO auditTaskResult = auditTaskMapper.selectOne(new QueryWrapper<AuditTaskDO>().eq("main_id", auditTaskId).orderByDesc("create_time").last("limit 1"));
        if (auditTaskResult == null) {
            return Result.fail("审核任务不存在");
        }
        // 通过审核任务id查询审核任务级别用户表，获取审核人信息
        AuditTaskLevelUserDO result = auditTaskLevelUserMapper.selectOne(new QueryWrapper<AuditTaskLevelUserDO>().eq("audit_task_id", auditTaskResult.getId()));
        if (result != null) {
            AuditFeedDo auditFeedDo = new AuditFeedDo();
            BeanUtils.copyProperties(result, auditFeedDo);
            return Result.ok(auditFeedDo);
        }
        return Result.fail();
    }

}
